package yang.VirtualMachine.chapter4;

import java.lang.ref.PhantomReference;
import java.lang.ref.ReferenceQueue;

/**
 * 1.虚引用加入的值，在任何时候返回为null
 * 2.虚引用的对象GC则清除，则加入到ReferenceQueue中
 * 3.若对象重载了finalize(),方法，则第一次GC会调用此方法,
 * 	此类型不能被立即回收。需继续GC才可
 * 4.若未重载，则立即回收，加入队列
 * 5.若对象在finalize()中复活，下次GC可回收时（无强引用）
 * 	直接回收,不重复执行finalize()方法。
 * @author xinxin
 *
 */
public class TraceCanReliveObj {
	public static TraceCanReliveObj obj;
	static ReferenceQueue<TraceCanReliveObj> phantomQueue = null;
	
	public static class CheckRefQueue extends Thread {
		@Override
		public void run() {
			while (true) {
				if (phantomQueue != null) {
					PhantomReference<TraceCanReliveObj> objt = null;
					try {
						objt = (PhantomReference<TraceCanReliveObj>) phantomQueue.remove();
					} catch (InterruptedException e){
						e.printStackTrace();
					}
				}
			}
		}
	}
	
	@Override
	protected void finalize() throws Throwable {
		super.finalize();
		System.out.println("CanReliveObj finalie called");
		obj = this; //此对象复活，（下次回收时不会调用此方法）
	}
	
	@Override
	public String toString() {
		return "I am CanReliveObj";
	}

	public static void main(String[] args) throws InterruptedException {
		Thread t = new CheckRefQueue();
		t.setDaemon(true);
		t.start();
		
		phantomQueue  = new ReferenceQueue<>();
		obj = new TraceCanReliveObj();
		PhantomReference<TraceCanReliveObj> phantomRef = new PhantomReference<TraceCanReliveObj>(obj, phantomQueue);
		System.out.println("phantomRef中值为：" + phantomRef.get());// 永远 null
		
		GCandCheck();
		GCandCheck();
		GCandCheck();
	}
	
	private static int gcTimes = 0;
	private static void GCandCheck() throws InterruptedException {
		obj = null;
		gcTimes++;
		System.out.printf("第%d次gc\n", gcTimes);
		System.gc();
		Thread.sleep(1000);
		if (obj == null) {
			System.out.println("obj 是 null");
		} else {
			System.out.println("obj 可用");
		}
	}

}
